//: \console -release -ofD:\usr\local\Apache2\install.exe

import
	tango.sys.win32.CodePage,
	tango.sys.win32.UserGdi,
	tango.sys.Process,
	tango.sys.Environment,
	Int	= tango.text.convert.Integer,
	Utf	= tango.text.convert.Utf,
	Txt	= tango.text.Util,
	Path	= tango.io.Path,
	tango.io.FilePath,
	tango.stdc.stringz,
	tango.core.Array,
	tango.io.Console,
	tango.io.device.File,
	tango.io.device.Array,
	tango.io.Stdout;
	
	extern(C) void exit(int);

struct Job{
	const char[] name;
	const void function() fun;
	bool 	isNewLine	= false ;
}

static const Job[] Jobs = [
	{"帮助", &help} ,
	{"安装配置文件", cast(void function()) &config1} ,
	{"语法检测", &config_check} ,
	{"版本信息", &version_info , true} ,
	
	{"安装为服务", &install} ,
	{"卸载服务", &uninstall , true} ,

	
	{"启动服务", &start} ,
	{"停止服务", &stop} ,
	{"重启服务", &restart, true} ,
	
	{"退出", &exit1} ,
];

static char[] RootDir , Httpd;
static bool isContinue = true ;
static const char[] HttpX	= "http2";
void main(char[][] args){
	__init;
	do{
		help;
	}while(isContinue);
}
void __init(){
	scope wchar[]   f;
	f.length   = 250;
	int i = GetModuleFileNameW(null, f.ptr, f.length);
	scope ExePath       = Utf.toString( f[0..i] );
	foreach(ref c ; ExePath) if( c == '\\' ) c = '/' ;
	int	j = rfind(ExePath, '/');
	RootDir	= ExePath[0..j].dup ;
	Httpd		= RootDir ~ r"/bin/httpd.exe";
}

void help(){
	Stdout("\n");
	foreach(int i, ref job; Jobs ){
		if( i ){
			Stdout(" ")( Int.toString(i) )(": ")(job.name)("\n");
			if( job.isNewLine ){
				Stdout("\n");
			}
		}
	}
	Stdout("    请输入: ").flush;
	auto opt	= Cin.get ;
	auto i	= Int.parse(opt);
	if( i < 0 || i >= Jobs.length ){
		i	= 0 ;
	}
	Stdout("\n").flush;
	Jobs[i].fun();
}


bool config1(){
	if( !config("httpd.conf", "conf") ){
		return false;
	}
	config("php.conf", "conf");
	config("vhost.conf", "conf");
	//config("php.ini", "php5");
	stdout("安装配置文件完毕!\n").flush;
	return true ;
}

bool  config(in char[] _f, in char[] _d){
	scope d	= RootDir ~ r"/etc/" ;
	scope char[] da;
	if( !Path.exists( d ) ){
		stdout("目录 `")(d)("` 不存在\n").flush;
		return false;
	}
	scope f	= d ~ _f ;
	if( !Path.exists( f ) ){
		stdout("文件 `")(f)("` 不存在\n").flush;
		return false;
	}
	try{
		da	= cast(char[]) File.get(f);
	}catch(Object e){
		stdout("读文件 `")(f)("` 失败\n").flush;
		return false;
	}
	scope da2	= Txt.substitute(da, `%&ROOT&%`, RootDir );
	
	scope d2	= RootDir ~ r"/" ~ _d ~ r"/" ;
	if( !Path.exists( d2 ) ){
		stdout("目录 `")(d2)("` 不存在\n").flush;
		return false;
	}
	scope f2	= d2 ~ _f;
	try{
		File.set(f2, da2);
	}catch(Object e){
		stdout("写文件 `")(f2)("` 失败\n").flush;
		return false;
	}
	return true ;
}

void exit1(){
	exit(0);
}

void install(){
	scope char[][] p	= [Httpd, "-k", "install", "-n", HttpX ];
	config1();
	exec(p, false);
}
void uninstall(){
	scope char[][] p	= [Httpd, "-k", "uninstall" , "-n", HttpX];
	exec(p, false);
}



void start(){
	scope char[][] p	= [Httpd, "-k", "start", "-n", HttpX];
	exec(p, false);
	show;
}
void stop(){
	scope char[][] p	= [Httpd, "-k", "stop", "-n", HttpX];
	exec(p, false);
	show;
}

void restart(){
	scope char[][] p	= [Httpd, "-k", "restart", "-n", HttpX];
	exec(p, false);
	show;
}

void version_info(){
	scope char[][] p	= [Httpd, "-v"];
	exec(p, false);
	show;
}

void config_check(){
	scope char[][] p	= [Httpd, "-t"];
	exec(p, false);
	show;
}



void exec(char[][] p, bool isNew = true ){
	if( isNew ){
		exec2(p);
	}else{
		scope proc = new Process (p, null);
		
		scope f	= proc.programName();
		
		if( !Path.exists( f ) ){
			stdout("可执行文件 `")(f)("` 不存在\n").flush;
			return ;
		}
		
		Stdout("执行命令: ");
		foreach(ref _p ; p ) Stdout(_p)(" ");
		Stdout("\n").flush;
		
		scope (exit) proc.close;
		proc.workDir = RootDir;
		proc.copyEnv (true);
		proc.execute();
		
		scope bu	= new Array(1024, 1024);
		bu.copy (proc.stderr);
		bu.copy (proc.stdout);
		scope ou	= cast(ubyte[]) bu.slice ;
		
		scope _bu		= new Array(1024, 1024);
		ubyte* eptr	= &ou[$-1];
		ubyte[2]		tmp ;
		
		bool isHex(ubyte v, ref ubyte _v){
			if( v >= '0' && v <= '9' ){
				_v	= v - '0' ;
				return true ;
			}
			if( v >= 'a' && v <= 'f' ){
				_v	= v - 'a' + 0xa;
				return true ;
			}
			if( v >= 'A' && v <= 'F' ){
				_v	= v - 'A' + 0xa;
				return true ;
			}
			return false ;
		}
		for(ubyte* ptr = &ou[0]; ptr< eptr; ptr++) {
			ubyte a, b ;
			if( ptr[0] is '\\' &&	ptr[1] is 'x' && isHex( ptr[2] , a ) && isHex(ptr[3], b) ){
				tmp[0]	= a * 0x10 + b  ;
				_bu(tmp[0..1]);
				ptr	+= 3;
			} else {
				tmp[0]	= ptr[0];
				_bu(tmp[0..1]);
			}
		}
		char[] _ou	= cast(char[]) _bu.slice ;
		char[1024 * 64] _tmp ;
		scope _re	= CodePage.from (_ou, _tmp);
		Stdout( _re )("\n").flush;
		
		auto result = proc.wait;
		if (result.reason != Process.Result.Exit){
			stdout("执行错误 `")(result.toString)("` \n").flush;
		}
		
	}
}

void exec2(in char[][] _cmd){
		int ret;
		scope path	= new FilePath(_cmd[0]);
		if( !path.exists ){
			auto file	= Environment.exePath(_cmd[0] ) ;
			if( !file.exists ){
				Stdout("Run file `")(path.toString)("` is not exists\n").flush;
				return ;
			}else{
				_cmd[0]	= file.toString;
				path		= file;
			}
		}
		
		Stdout("Run: ");
		foreach(ref _p ; _cmd ) Stdout(_p)(" ");
		Stdout("\n").flush;
	
		char[] RunDir	=  RootDir ;

		wchar* pDir	= toString16z(Utf.toString16( RunDir ));
		wchar* pFile	= toString16z(Utf.toString16(  path.toString ));
		wchar* parg	= toString16z(Utf.toString16( Txt.join(_cmd[1..$],  " ") ));
		
		DWORD dwCreationFlags	=CREATE_NEW_PROCESS_GROUP;
		
		STARTUPINFO si;
		si.cb			= STARTUPINFO.sizeof;
		si.dwFlags 		= STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
		si.wShowWindow	= SW_SHOW; // SW_HIDE;et
		
		si.hStdInput	= GetStdHandle(STD_INPUT_HANDLE) ;
		si.hStdOutput	= GetStdHandle(STD_OUTPUT_HANDLE) ;
		si.hStdError		= GetStdHandle(STD_ERROR_HANDLE);
		
		PROCESS_INFORMATION pi;
		ret = CreateProcessW(
				  pFile,
				  parg,
				  null, null,	//LPSECURITY_ATTRIBUTES
				  TRUE,
				  dwCreationFlags ,
				  null, //环境
				  pDir, //目录
				  &si, 
				  &pi);
		if( ret is 0 ){
			Stdout.formatln("exec: {}", fromString16z(pFile) ).flush;
			return ;
		}
		ret	= WaitForSingleObject(pi.hProcess, INFINITE);
		if( WAIT_OBJECT_0 != ret ){
			TerminateProcess(pi.hProcess, 1);
		}else{
			uint exitcode;
			GetExitCodeProcess(pi.hProcess, &exitcode);
		}
	}

void show(){
	
}